# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
# File       : parallel_node_utils.py
# Time       ：2024/8/27 22:21
# Author     ：author name
# version    ：python 3.10
# Description：并行网关节点
"""
import uuid
from typing import List

from apis.orderlines.models import Task
from public.base_model import session_scope
from public.logger import logger
from public.utils.const import DEFAULT_CONFIG


class ParallelNodeUtils(object):

    def __init__(self, process_id: str, nodes: List[dict]):
        self.nodes = nodes
        self.process_id = process_id
        self.parallel_start_nodes: List[str] = []
        self.parallel_end_nodes: List[str] = []
        self.get_parallel_start_nodes()
        self.get_parallel_end_nodes()
        if len(self.parallel_start_nodes) != len(self.parallel_end_nodes):
            raise ValueError(f'并行开始{self.parallel_start_nodes}和并行结束节点{self.parallel_end_nodes}数量不一致')

    def get_parallel_start_nodes(self):
        for node in self.nodes:
            if node.get('type') == 'parallel-node' and node.get('task_name') == '并行开始':
                self.parallel_start_nodes.append(node.get('task_id'))

    def get_parallel_end_nodes(self):
        for node in self.nodes:
            if node.get('type') == 'parallel-node' and node.get('task_name') == '并行结束':
                self.parallel_end_nodes.append(node.get('task_id'))

    @staticmethod
    def find_parallel_paths(tasks, start_node, end_node):
        # 存储所有路径的列表
        all_paths = []

        # 用于存储已经访问过的节点的集合
        visited = set()

        # 深度优先搜索 (DFS) 函数
        def dfs(current_path, current_node):
            if current_node == end_node:
                # 如果当前节点是结束节点，则添加当前路径到所有路径列表
                all_paths.append(current_path + [current_node])
                return

            # 获取当前任务的所有下一个任务ID
            for task in tasks:
                if task['task_id'] == current_node:
                    next_ids = task['next_id'].split(',') if task['next_id'] else [None]
                    for next_id in next_ids:
                        if next_id not in visited:
                            visited.add(next_id)
                            dfs(current_path + [current_node], next_id)
                            visited.remove(next_id)

        # 从开始节点开始遍历
        dfs([], start_node)

        filtered_paths = []
        for path in all_paths:
            temp = []
            for node in path:
                if node != start_node and node != end_node:
                    temp.append(node)
            filtered_paths.append(temp)

        return filtered_paths

    def build_vir_task_group(self, parallel_start_task_id: str, parallel_end_task_id: str, task_ids: List[str]):
        """创建虚拟任务组"""
        task_id = str(uuid.uuid4())
        group_node = {
            'task_id': task_id,
            'task_name': f'{parallel_end_task_id}-group',
            'prev_id': parallel_start_task_id,
            'next_id': parallel_end_task_id,
            'method_name': 'task_group',
            'task_type': 'group',
            'task_module': 'Group',
            'method_kwargs': {'group_ids': task_ids},
            'task_config': DEFAULT_CONFIG,
            'process_id': self.process_id,
        }
        with session_scope() as session:
            obj = Task(**group_node)
            session.add(obj)
            session.commit()
        return task_id

    @staticmethod
    def delete_vir_task_group(parallel_start_task_id):
        """删除虚拟任务组， 每个虚拟"""
        with session_scope() as session:
            session.query(Task).filter(
                Task.task_name.like(f'%{parallel_start_task_id}%'),
                Task.active == 1,
                Task.task_type == 'group'
            ).delete()
            session.commit()

    def handle_parallel_node(self, index):
        sorted_task_id = []
        parallel_task_ids = []

        parallel_start_task_id = str(self.parallel_start_nodes[index])
        parallel_end_task_id = str(self.parallel_end_nodes[index])
        sorted_task_id.append(parallel_start_task_id)
        sorted_task_id.append(parallel_end_task_id)

        self.delete_vir_task_group(parallel_start_task_id)
        parallel_paths = self.find_parallel_paths(self.nodes, parallel_start_task_id, parallel_end_task_id)
        logger.info(f'并行网关节点::{parallel_paths}')
        for path in parallel_paths:
            vir_group_task_id = self.build_vir_task_group(parallel_start_task_id, parallel_end_task_id, path)
            parallel_task_ids.append(vir_group_task_id)

        return sorted_task_id, parallel_task_ids
